package plot
{
	import flash.events.MouseEvent;
	
	import mx.binding.utils.BindingUtils;
	import mx.collections.ArrayCollection;
	import mx.containers.Canvas;
	import mx.controls.Label;
	import mx.managers.CursorManager;	
	

	public class PlotBitmap extends Canvas
	{
		
		
		/**
		 * Expects a two-dimensional array
		 * each column in the array is a property
		 * each row in the array is one variable
		 * Example:
		 * date			time	expenses
		 * 12/12/03		12:30	3.45
		 * 12/12/03		4:30	6.88
		 * 12/13/03		9:30	2.32
		 * 
		 * dataProvider = [
		 * {'12/12/03', '12:30', 3.45},
		 * {'12/12/03', '4:30', 6.88},
		 * {'12/13/03', '9:30', 2.32}
		 * ]
		 * 
		 * 
         */   
       
        
        [Bindable]
        public function get dataProvider():ArrayCollection
        {
        	return _dataProvider;
        }
        public function set dataProvider(value:ArrayCollection):void
        {
        	// TODO: infer variablesNames
        	if (value != _dataProvider){
				_dataProvider = value;
				callLater(init);
			}
	    }
        private var _dataProvider:ArrayCollection;
        
        // TODO: infer label names from the data provider
       	[Bindable]
        public function get labels():ArrayCollection
        {
        	return _labels;
        }
        public function set labels(value:ArrayCollection):void
        {
        	if (value != null && value.length > 0){
        		if (value[0].hasOwnProperty("Name"))
        		{
        			// get just the names
        			_labels= new ArrayCollection();
        			for each (var item:Object in value)
        			{
        				_labels.addItem(item.Name);
        			}
        		}
        		else 
        		{
        			_labels = value;
        		}
        		
        		
//        		removeLabels();
//        		addLabels();
        	}
        }
        private var _labels:ArrayCollection;
		
		[Bindable]
		public var verticalTextIndent:int = 5;
		
		[Bindable]
		public var horizontalTextIndent:int = -5;
		
		[Bindable]
		public var paddingTop:int = 30;
		
		[Bindable]
		public var paddingLeft:int = 30;
        
        [Bindable]
        public var selectedItems:ArrayCollection = new ArrayCollection();
        
        [Bindable]
        public var itemColor:uint = 0x0000ff;
        
        [Bindable]
        public function get lineThickness():int
        {
        	return _lineThickness;
        }
        public function set lineThickness(value:int):void
        {
        	var update:Boolean = false;
        	if (value != _lineThickness)
        		update = true;
        	if (value > 0)
        		_lineThickness = value;
        	else
        		_lineThickness = 1;
        	
        	if (update)
        		updateThickness();	
        }
        private var _lineThickness:int = 1;
        
        [Bindable]
        public function get opacity():Number
        {
        	return _opacity;
        }
        public function set opacity(value:Number):void
        {
        	var update:Boolean = false;
        	if (value != _opacity) update = true;
        	if (value > 0) _opacity = value;
        		else _opacity = 0.1;
        	
        	if (update) updateOpacity();
        }
        private var _opacity:Number = 0.5;
        
        //---------------------------------------------------------------------
        //
        // Private variables
        //
        //---------------------------------------------------------------------
        
        private var column_count:int;
        private var grid:Grid;
        private var lines:Lines;
        private var dataManager:DataManager;
        
        
        public function PlotBitmap()
		{
			super();
			trace("in constructor");
			percentHeight = 100;
			percentWidth = 100;
			clipContent = false;
			dataManager = new DataManager();
		}
        
        //---------------------------------------------------------------------
        //
        // Calculations
        //
        //---------------------------------------------------------------------
        
        private function init():void{
        	trace("init");
        	
        	CursorManager.setBusyCursor();
        	
        	column_count = labels.length;
        	drawGrid();
        	drawSeries();
        	        	
        	CursorManager.removeBusyCursor();
        }
        
        /**
        * Draw grid
        */
        private function drawGrid():void
        {
			grid = new Grid();
			
			BindingUtils.bindProperty(grid, "axesProvider", this, "labels");
			BindingUtils.bindProperty(grid, "verticalTextIndent", this, "verticalTextIndent"); 
			BindingUtils.bindProperty(grid, "horizontalTextIndent", this, "horizontalTextIndent");

			addChild(grid);
		}
        
        /**
        * Draw parallel series
        */
        private function drawSeries():void
        {
        	lines = new Lines();
        	BindingUtils.bindProperty(lines, "dataProvider", dataManager, "processedData");
        	BindingUtils.bindProperty(lines, "minimumValues", dataManager, "minimumValues");
        	BindingUtils.bindProperty(lines, "maximumValues", dataManager, "maximumValues");
        	lines.dataProvider = this.dataProvider;
        	addChild(lines);
        }
        
//        private function addLabels():void
//        {
//        	trace("addLabels");
//        	CursorManager.setBusyCursor();
//        	
//        	var label:Label;
//        	var colWidth:int = (this.width - 2 * paddingTop) / (column_count - 1);
//        	
//        	for (var i:int; i < labels.length; i++)
//        	{
//        		label = new Label();
//        		label.text = labels[i];
////				label.text = "blah";
//        		label.setStyle("paddingLeft", 0);
//        		label.setStyle("paddingRight", 0);
//        		label.setStyle("paddingTop", 0);
//        		label.setStyle("paddingBottom", 0);
//        		
//        		// TODO: how to avoid setting width and height?
//        		label.width = 100;
//        		label.height = 21;
//        		
//        		addChild(label);
//        		_labelsArr.addItem(label);
//        	}
//        	
//        	CursorManager.removeBusyCursor();
//        }
        
//        private function removeLabels():void
//        {
//        	trace("removing labels");
//        	for each (var label:Label in _labelsArr)
//        	{
//        		removeChild(label);
//        	}
//        	_labelsArr.removeAll();
//        }
        
        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
        	trace("updating graph " + unscaledWidth + " " + unscaledHeight );
        	grid.move(paddingTop, paddingLeft);
        	grid.setActualSize(unscaledWidth - paddingLeft * 2, unscaledHeight - paddingTop);
        	
        	// position labels
//        	var colWidth:int = (unscaledWidth - 2 * paddingTop) / (column_count - 1);
//        	var yCoord:int = unscaledHeight - paddingLeft + verticalTextIndent;
//        	var numLabels:int = _labelsArr.length;
//        	for (var i:int = 0; i < numLabels; i++)
//        	{
//        		Label(_labelsArr[i]).move(
//        			paddingTop + i * colWidth + horizontalTextIndent,
//        		 	yCoord);
//        	}
        	
        	lines.setActualSize(unscaledWidth - this.paddingTop * 2, unscaledHeight - this.paddingLeft * 2);
        	lines.move(paddingTop, paddingLeft);
        }        
        
        //---------------------------------------------------------------------
        //
        // Event handlers
        //
        //---------------------------------------------------------------------
        
        private function updateThickness():void
        {
        	trace("updating thickness");
//        	for (var i:int = 0; i < dataProvider.length; i++){
//        		(lines.getItemAt(i) as PCPLine).thickness = this.lineThickness;
//        	}
        }
        private function updateOpacity():void
        {
        	trace("updating opacity");
//        	for (var i:int = 0; i < dataProvider.length; i++){
//        		(lines.getItemAt(i) as PCPLine).opacity = this.opacity;
//        	}
        }
        
        private function handleLineMouseClick(e:MouseEvent):void
        {
        	trace("handleLineMouseClick " + new Date().toString());
        	
//        	var line:PCPLine = e.currentTarget as PCPLine;
//        	if (line.selected)
//        		selectedItems.addItem(line.coordData);
//        	else
//        		selectedItems.removeItemAt(selectedItems.getItemIndex(line.coordData));
        }		
	}
}